namespace BitBlazorUI {
    export class DataGrid {
        public static init(tableElement: any) {
            DataGrid.enableColumnResizing(tableElement);

            const bodyClickHandler = (event: any) => {
                const columnOptionsElement = tableElement.tHead.querySelector('.bit-dtg-cop');
                if (columnOptionsElement && event.composedPath().indexOf(columnOptionsElement) < 0) {
                    tableElement.dispatchEvent(new CustomEvent('closecolumnoptions', { bubbles: true }));
                }
            };
            const keyDownHandler = (event: any) => {
                const columnOptionsElement = tableElement.tHead.querySelector('.bit-dtg-cop');
                if (columnOptionsElement && event.key === "Escape") {
                    tableElement.dispatchEvent(new CustomEvent('closecolumnoptions', { bubbles: true }));
                }
            };

            document.body.addEventListener('click', bodyClickHandler);
            document.body.addEventListener('mousedown', bodyClickHandler); // Otherwise it seems strange that it doesn't go away until you release the mouse button
            document.body.addEventListener('keydown', keyDownHandler);

            return {
                stop: () => {
                    document.body.removeEventListener('click', bodyClickHandler);
                    document.body.removeEventListener('mousedown', bodyClickHandler);
                    document.body.removeEventListener('keydown', keyDownHandler);
                }
            };
        }

        public static checkColumnOptionsPosition(tableElement: any) {
            const colOptions = tableElement.tHead && tableElement.tHead.querySelector('.bit-dtg-cop'); // Only match within *our* thead, not nested tables
            if (colOptions) {
                // We want the options popup to be positioned over the grid, not overflowing on either side, because it's possible that
                // beyond either side is off-screen or outside the scroll range of an ancestor
                const gridRect = tableElement.getBoundingClientRect();
                const optionsRect = colOptions.getBoundingClientRect();
                const leftOverhang = Math.max(0, gridRect.left - optionsRect.left);
                const rightOverhang = Math.max(0, optionsRect.right - gridRect.right);
                if (leftOverhang || rightOverhang) {
                    // In the unlikely event that it overhangs both sides, we'll center it
                    const applyOffset = leftOverhang && rightOverhang ? (leftOverhang - rightOverhang) / 2 : (leftOverhang - rightOverhang);
                    colOptions.style.transform = `translateX(${applyOffset}px)`;
                }

                colOptions.scrollIntoViewIfNeeded();

                const autoFocusElem = colOptions.querySelector('[autofocus]');
                if (autoFocusElem) {
                    autoFocusElem.focus();
                }
            }
        }

        private static enableColumnResizing(tableElement: any) {
            tableElement.tHead.querySelectorAll('.bit-dtg-drg').forEach((handle: any) => {
                handle.addEventListener('mousedown', handleMouseDown);
                if ('ontouchstart' in window) {
                    handle.addEventListener('touchstart', handleMouseDown);
                }

                function handleMouseDown(evt: any) {
                    evt.preventDefault();
                    evt.stopPropagation();

                    const th = handle.parentElement;
                    const startPageX = evt.touches ? evt.touches[0].pageX : evt.pageX;
                    const originalColumnWidth = th.offsetWidth;
                    const rtlMultiplier = window.getComputedStyle(th, null).getPropertyValue('direction') === 'rtl' ? -1 : 1;
                    let updatedColumnWidth = 0;

                    function handleMouseMove(evt: any) {
                        evt.stopPropagation();
                        const newPageX = evt.touches ? evt.touches[0].pageX : evt.pageX;
                        const nextWidth = originalColumnWidth + (newPageX - startPageX) * rtlMultiplier;
                        if (Math.abs(nextWidth - updatedColumnWidth) > 0) {
                            updatedColumnWidth = nextWidth;
                            th.style.width = `${updatedColumnWidth}px`;
                        }
                    }

                    function handleMouseUp() {
                        document.body.removeEventListener('mousemove', handleMouseMove);
                        document.body.removeEventListener('mouseup', handleMouseUp);
                        document.body.removeEventListener('touchmove', handleMouseMove);
                        document.body.removeEventListener('touchend', handleMouseUp);
                    }

                    if (window.TouchEvent && evt instanceof TouchEvent) {
                        document.body.addEventListener('touchmove', handleMouseMove, { passive: true });
                        document.body.addEventListener('touchend', handleMouseUp, { passive: true });
                    } else {
                        document.body.addEventListener('mousemove', handleMouseMove, { passive: true });
                        document.body.addEventListener('mouseup', handleMouseUp, { passive: true });
                    }
                }
            });
        }
    }
}
